//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_LOCKQUEUE_HPP
#define RS_LOCKQUEUE_HPP

#include "rs/Condition.hpp"
#include "rs/Mutex.hpp"
#include "rs/ScopedLock.hpp"
#include <queue>

namespace rs
{
	namespace concurrency
	{
		// A multiproducer, multiconsumer queue based on:
		// http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
		template< typename T >
		class LockQueue
		{
		public:
			
			typedef T ValueType;
			
		public:
			
			Boolean IsEmpty() const;
			
			void Push(T const& value);
			
			Boolean TryPop(T& out);
			
			void WaitPop(T& out);
			
		private:
			
			std::queue< T > queue_;
			mutable Mutex mutex_;
			Condition condition_;
		};
		
		
		template< typename T >
		inline Boolean LockQueue< T >::IsEmpty() const {
			ScopedLock< Mutex > lock(mutex_);
			return queue_.empty();
		}
		
		template< typename T >
		inline void LockQueue< T >::Push(T const& value) {
			mutex_.Lock();
			queue_.push(value);
			mutex_.Unlock();
			condition_.Signal();
		}
		
		template< typename T >
		inline Boolean LockQueue< T >::TryPop(T& out) {
			ScopedLock< Mutex > lock(mutex_);
			if (queue_.empty()) {
				return false;
			}
			
			out = queue_.front();
			queue_.pop();
			return true;
		}
		
		template< typename T >
		inline void LockQueue< T >::WaitPop(T& out) {
			ScopedLock< Mutex > lock(mutex_);
			while (queue_.empty()) {
				condition_.Wait(mutex_);
			}
			
			out = queue_.front();
			queue_.pop();
		}
	}
}

#endif // RS_LOCKQUEUE_HPP
